
///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2002, Perry L. Miller IV
//  All rights reserved.
//  BSD License: http://www.opensource.org/licenses/bsd-license.html
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//
//  Mutex class.
//
//  Should this file be split into 2 implementation files?
//  MutexWin32.cpp and MutexPThreads.cpp?
//
//  For critical section objects see:
//  http://msdn.microsoft.com/en-us/library/ms682530.aspx
//
//  For pthreads see:
//  https://computing.llnl.gov/tutorials/pthreads/
//
///////////////////////////////////////////////////////////////////////////////

#include "Usul/Threads/Mutex.h"
#include "Usul/Exceptions/TimedOut.h"
#include "Usul/Strings/Format.h"
#include "Usul/System/Clock.h"
#include "Usul/System/Sleep.h"

#include <stdexcept>

#ifdef __GNUC__
# include <errno.h>
#endif

using namespace Usul::Threads;


///////////////////////////////////////////////////////////////////////////////
//
//  Constructor.
//
///////////////////////////////////////////////////////////////////////////////

Mutex::Mutex() :
#ifdef USUL_WINDOWS
  _cs()
#endif
#ifdef __GNUC__
  _mutex()
#endif
{
#ifdef USUL_WINDOWS
  ::InitializeCriticalSection( &_cs );
#endif

#ifdef __GNUC__
  // This function may return an error.  Should we throw?
  ::pthread_mutex_init ( &_mutex, 0x0 );
#endif
}


///////////////////////////////////////////////////////////////////////////////
//
//  Destructor.
//
///////////////////////////////////////////////////////////////////////////////

Mutex::~Mutex()
{
#ifdef USUL_WINDOWS
  ::DeleteCriticalSection( &_cs );
#endif

#ifdef __GNUC__
  ::pthread_mutex_destroy ( &_mutex );
#endif
}


///////////////////////////////////////////////////////////////////////////////
//
//  Create the mutex.
//
///////////////////////////////////////////////////////////////////////////////

Mutex *Mutex::create()
{
  return new Mutex();
}


///////////////////////////////////////////////////////////////////////////////
//
//  Lock the mutex.
//
///////////////////////////////////////////////////////////////////////////////

void Mutex::lock()
{
#ifdef USUL_WINDOWS
  ::EnterCriticalSection ( &_cs );
#endif

#ifdef __GNUC__
  ::pthread_mutex_lock ( &_mutex );
#endif

}


///////////////////////////////////////////////////////////////////////////////
//
//  Unlock the mutex.
//
///////////////////////////////////////////////////////////////////////////////

void Mutex::unlock()
{
#ifdef USUL_WINDOWS
  ::LeaveCriticalSection ( &_cs );
#endif

#ifdef __GNUC__
  ::pthread_mutex_unlock ( &_mutex );
#endif
}
